﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization.Json;
using System.Reflection;

namespace Wyse.Server.Base
{
    /// <summary>
    /// Manages message types
    /// </summary>
    public static class MessageTypeMgr
    {
        /// <summary>
        /// Gets the data serializer for the specified action
        /// </summary>
        /// <param name="action"></param>
        /// <returns></returns>
        public static DataContractJsonSerializer GetSerializer(String action)
        {
            lock (sSync)
            {
                if (sTypes == null)
                    GetTypes();

                MessageTypeEntry e;
                if (sTypes.TryGetValue(action, out e))
                {
                    if (e.Serializer == null)
                        e.Serializer = new DataContractJsonSerializer(e.DataType);
                    return e.Serializer;
                }

                return null;
            }
        }

        /// <summary>
        /// Sets the assmebly which will be used to search for message
        /// types (to be used only from unit tests)
        /// </summary>
        /// <param name="asm"></param>
        public static void SetMainAssembly(Assembly asm)
        {
            lock (sSync)
            {
                sMainAssembly = asm;
            }
        }

        /// <summary>
        /// Stores information about a single message type
        /// </summary>
        private class MessageTypeEntry
        {
            public String Action;
            public Type DataType;
            public DataContractJsonSerializer Serializer;
        }

        private static void GetTypes()
        {
            sTypes = new Dictionary<string, MessageTypeEntry>();

            Assembly asm = sMainAssembly ?? Assembly.GetExecutingAssembly();

            foreach (var t in asm.GetExportedTypes())
            {
                Object[] attrs = t.GetCustomAttributes(typeof(MessageDataAttribute), false);
                if (attrs.Length == 0)
                    continue;
                MessageDataAttribute mda = (MessageDataAttribute)attrs[0];

                if (String.IsNullOrWhiteSpace(mda.Action))
                    continue;

                sTypes[mda.Action] = new MessageTypeEntry()
                {
                    Action = mda.Action,
                    DataType = t
                };
            }
        }

        private static Assembly sMainAssembly;
        private static Object sSync = new object();
        private static Dictionary<String, MessageTypeEntry> sTypes;
    }
}
